package com.ymtms.settlement.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ymtms.settlement.dao.CollectingMoneyBalanceMapper;
import com.ymtms.settlement.dao.CollectionBusinessParametersMapper;
import com.ymtms.settlement.dao.GoodsbillMasterMapper;
import com.ymtms.settlement.pojo.CollectingMoneyBalance;
import com.ymtms.settlement.pojo.CollectionBusinessParameters;
import com.ymtms.settlement.pojo.GoodsbillMaster;
import com.ymtms.settlement.service.CollectingMoneyBalanceService;
import com.ymtms.settlement.vo.GridRequest;
import com.ymtms.settlement.vo.GridResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class CollectingMoneyBalanceServiceImpl implements CollectingMoneyBalanceService {
    @Autowired
    CollectingMoneyBalanceMapper collectingMoneyBalanceMapper;
    @Autowired
    GoodsbillMasterMapper goodsbillMasterMapper;
    @Autowired
    CollectionBusinessParametersMapper collectionBusinessParametersMapper;

    /*---------------------------代收结算业务------------------------------*/

    /**
     * @description: 多条件分页查询代收结算项
     * @param gridRequest 封装包含分页信息的对象（当前页、页大小、排序字段、排序规则）
     * @param goodsbillMaster 封装查询条件实体对象
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return: GridResult 返回符合Layui格式的查询的结果
     * @author: 邱斌雨
     * @date: 2019/11/2
     */
    @Override
    public GridResult<GoodsbillMaster> queryGbmByPage(
            GridRequest gridRequest, GoodsbillMaster goodsbillMaster,
            String startTime, String endTime) {
        // 获取当前页和页大小
        Integer currentPage = gridRequest.getPage();
        Integer pageSize = gridRequest.getLimit();

        // 判断是否有排序,有则生成符合pagehelper的排序字符串
        String sidx = gridRequest.getSidx(); // 排序参数
        String sord = gridRequest.getSord(); // 排序规则


        String orderBy = "";
        // pagehelper静态设置页属性方法，它会拦截下面的第一个查询！第二个无效。
        if(checkOrderBy(sidx, sord)){
            sidx = upperCharToUnderLine(sidx);
            orderBy = sidx+" "+sord;

            PageHelper.startPage(currentPage, pageSize, orderBy);
        }else{
            // 设置当前页和页大小
            PageHelper.startPage(currentPage, pageSize);
        }

        // 查询结果（传入排序）
        List<GoodsbillMaster> result = goodsbillMasterMapper.selectByIfSettleAccounts(goodsbillMaster, startTime, endTime);

        // 利用当前页和页大小配置pageinfo
        PageInfo<GoodsbillMaster> pageList = new PageInfo<>(result);
        // 新建一个封装类对象，设置参数，传入查询得到的数据
        GridResult<GoodsbillMaster> grid = new GridResult<>();

        // 存入查询数据
        grid.setData(result);
        // 存入总条数
        grid.setCount(pageList.getTotal());

        return grid;
    }

    /**
     * @description: 根据gmid查询符合条件的代收结算项
     * @param gmid 货运单主表主键
     * @return: 包含货运单信息的GoodsbillMaster对象
     * @author: 邱斌雨
     * @date: 2019/11/2
     */
    @Override
    public GoodsbillMaster queryGbmByGmid(Integer gmid) {
        GoodsbillMaster result = goodsbillMasterMapper.selectByGmid(gmid);
        return result;
    }


    /**
     * @description: 根据gmid查询校验并执行代收结算
     * @param gmid 货运单主表主键
     * @param collectingMoneyBalance 封装新增到代收结算表参数的对象
     * @return: void 包含新增操作结果的map对象
     * @author: 邱斌雨
     * @date: 2019/11/2
     */
    @Override
    public void save(Integer gmid, CollectingMoneyBalance collectingMoneyBalance) {

        // 1. 根据id查询对应数据
        GoodsbillMaster goodsbillMaster = goodsbillMasterMapper.selectByGmid(gmid);
        /* 如果未查到（有可能已被修改），则抛出异常 */
        if(goodsbillMaster == null){
            throw new RuntimeException("结算失败，未找到对应数据！");
        }

        // 2. 核对数据

        // 2.1 从数据库中获取该项的信息
        /* 获取数据库中该项的应收货款和代收货款变更、佣金费率 */
        BigDecimal receivable = goodsbillMaster.getHelpAcceptPayment();
        BigDecimal changePay = goodsbillMaster.getPayKickback();
        BigDecimal rate = new BigDecimal(goodsbillMaster.getAcceptprocedureRate());
        /* 代收货款参数组,包括最高-最低佣金费、最高可代收货款 */
        String[] collectionParamters = goodsbillMaster.getReceiveGoodsCustomerMobile().split(",");
        BigDecimal minLimit = new BigDecimal(collectionParamters[1]);
        BigDecimal maxLimit = new BigDecimal(collectionParamters[2]);

        // 2.2 应收货款核对（主要为了校验业务变更）
        /* 校验代收货款变更，为-1表示有变更，为0表示该业务取消 */

        int compare = BigDecimal.ZERO.compareTo(changePay);
        if(compare == -1) {
            receivable = changePay;
        }else if(compare == 0){
            throw new RuntimeException("结算失败，该项的代收货款业务已被删除或取消！");
        }
        /* 校验变更货款是否相等 */
        if(changePay.compareTo(collectingMoneyBalance.getGoodsPaychange())!=0){
            throw new RuntimeException("结算失败，货款变更已变化，请刷新页面！");
        }

        /* 获取前台传来的实收货款 */
        BigDecimal fact = collectingMoneyBalance.getFactReceivefund();

        /* 判断当前应收货款与实收货款是否一致 */
        if(BigDecimal.ZERO.compareTo(receivable.subtract(fact))!=0){
            throw new RuntimeException("结算失败，应收货款与实收货款不一致");
        }

        // 2.3 应收佣金核对
        /* 佣金率核对 */
        Float factRate = collectingMoneyBalance.getCommisionRate();
        if(rate.floatValue() != factRate){
            throw new RuntimeException("结算失败，佣金率已经变化，请刷新页面！");
        }
        System.out.println(rate);
        /* 计算应收佣金（四舍五人） */
        BigDecimal mult = rate.multiply(receivable).setScale(2,BigDecimal.ROUND_HALF_UP);


        /* 检查是否小于最小佣金费用，是则赋值 */
        if(minLimit.compareTo(mult)> 0){
            mult = minLimit;
        }
        /* 检测是否大于最大佣金费用，是则赋值 */
        if(maxLimit.compareTo(mult)< 0){
            mult = maxLimit;
        }

        /* 获取前台实收佣金并，判断佣金是否一致 */
        if(collectingMoneyBalance.getReceivedCommision().compareTo(mult)!= 0){
            throw new RuntimeException("结算失败，应收佣金与实收佣金不一致");
        }
        // 3. 保存数据
        // 3.1 修改goodsbill_master表中的结账状态
        int gbmupdate = goodsbillMasterMapper.updateIfSettleAccountsByGmid(gmid);
        // 3.2 添加到collection_money_balance表中
        /* 获取并保存运单号、用户名、佣金率、应收货款、货款变更、应收佣金、结算时间，实收向已在对象中 */
        collectingMoneyBalance.setGoodsBillCode(goodsbillMaster.getGoodsBillCode());
        collectingMoneyBalance.setCustomer(goodsbillMaster.getSendGoodsCustomer());
        collectingMoneyBalance.setCommisionRate(rate.floatValue());
        collectingMoneyBalance.setAccountReceivable(goodsbillMaster.getHelpAcceptPayment());
        collectingMoneyBalance.setCommisionReceivable(mult);
        collectingMoneyBalance.setBalanceDate(new Date());
        int cmbupdate = collectingMoneyBalanceMapper.insertFinally(collectingMoneyBalance);
        if(gbmupdate == 0 || cmbupdate == 0){
            throw new RuntimeException("结算失败，未找到对应数据！");
        }
    }

    /*-----------------------------代收结算历史业务------------------------------*/

    /**
     * @description: 多条件分页查询代收结算历史
     * @param gridRequest 封装包含分页信息的类（当前页、页大小、排序字段、排序规则）
     * @param collectingMoneyBalance 包含查询条件的实体类
     * @param startTime 时间范围查询条件（开始时间）
     * @param endTime 时间范围查询条件（结束时间）
     * @return: 返回类包含实体类集合和前端layui分页条件
     * @author: 邱斌雨
     * @date: 2019/10/25
     */
    @Override
    public GridResult<CollectingMoneyBalance> queryCmbByPage(
            GridRequest gridRequest, CollectingMoneyBalance collectingMoneyBalance,
            String startTime, String endTime) {

        // 获取当前页和页大小
        Integer currentPage = gridRequest.getPage();
        Integer pageSize = gridRequest.getLimit();

        // 判断是否有排序,有则生成符合pagehelper的排序字符串
        String sidx = gridRequest.getSidx(); // 排序参数
        String sord = gridRequest.getSord(); // 排序规则


        String orderBy = "";
        // pagehelper静态设置页属性方法，它会拦截下面的第一个查询！第二个无效。
        if(checkOrderBy(sidx, sord)){
            sidx = upperCharToUnderLine(sidx);
            orderBy = sidx+" "+sord;

            PageHelper.startPage(currentPage, pageSize, orderBy);
        }else{
            // 设置当前页和页大小
            PageHelper.startPage(currentPage, pageSize);
        }

        // 查询结果（传入排序）
        List<CollectingMoneyBalance> result = collectingMoneyBalanceMapper.selectByCondition(collectingMoneyBalance, startTime, endTime);

        // 利用当前页和页大小配置pageinfo
        PageInfo<CollectingMoneyBalance> pageList = new PageInfo<>(result);
        // 新建一个封装类对象，设置参数，传入查询得到的数据
        GridResult<CollectingMoneyBalance> grid = new GridResult<>();

        // 存入查询数据
        grid.setData(result);
        // 存入总条数
        grid.setCount(pageList.getTotal());

        return grid;
    }

    /**
     * @description: 软删除
     * @param cmsid 表主键
     * @return: int
     * @author: 邱斌雨
     * @date: 2019/10/25
     */
    @Override
    public int removeByCmsid(Integer cmsid) {
        return collectingMoneyBalanceMapper.deleteByCmsid(cmsid);
    }

    /**
     * @description: 批量软删除
     * @param keys 表主键数组
     * @return: int
     * @author: 邱斌雨
     * @date: 2019/10/25
     */
    @Override
    public int batchRemoveByCmsid(Integer[] keys) {
        return collectingMoneyBalanceMapper.batchDeleteByCmsid(keys);
    }


    /*--------------------------------业务变更------------------------------*/

    @Override
    public GridResult<GoodsbillMaster> queryChangeAbleGbmByPage(GridRequest gridRequest, GoodsbillMaster goodsbillMaster) {
        // 获取当前页和页大小
        Integer currentPage = gridRequest.getPage();
        Integer pageSize = gridRequest.getLimit();

        // 判断是否有排序,有则生成符合pagehelper的排序字符串
        String sidx = gridRequest.getSidx(); // 排序参数
        String sord = gridRequest.getSord(); // 排序规则


        String orderBy = "";
        // pagehelper静态设置页属性方法，它会拦截下面的第一个查询！第二个无效。
        if(checkOrderBy(sidx, sord)){
            sidx = upperCharToUnderLine(sidx);
            orderBy = sidx+" "+sord;

            PageHelper.startPage(currentPage, pageSize, orderBy);
        }else{
            // 设置当前页和页大小
            PageHelper.startPage(currentPage, pageSize);
        }

        // 查询结果（传入排序）
        List<GoodsbillMaster> result = goodsbillMasterMapper.selectChangeAbleGmb(goodsbillMaster);

        // 利用当前页和页大小配置pageinfo
        PageInfo<GoodsbillMaster> pageList = new PageInfo<>(result);
        // 新建一个封装类对象，设置参数，传入查询得到的数据
        GridResult<GoodsbillMaster> grid = new GridResult<>();

        // 存入查询数据
        grid.setData(result);
        // 存入总条数
        grid.setCount(pageList.getTotal());

        return grid;
    }

    @Override
    public GoodsbillMaster queryChanegAbleGbmByGmid(Integer gmid) {
        GoodsbillMaster result = goodsbillMasterMapper.selectChanegAbleGbmByGmid(gmid);
        return result;
    }

    @Override
    public void cancelBusiness(Integer gmid) {
        int result = goodsbillMasterMapper.updateSetCancelCollectionBusinessByGmid(gmid);
        if(result==0){
            throw new RuntimeException("取消失败，未找到该项运单，请确认该运单的状态!");
        }
    }

    @Override
    public void addBusiness(GoodsbillMaster goodsbillMaster) {
        // 先要获取指定业务的参数
        CollectionBusinessParameters parameters = collectionBusinessParametersMapper.selectBytype(goodsbillMaster.getSendGoodsCustomerMobile());
        if(parameters==null){
            throw new RuntimeException("添加失败，请检查业务是否存在");
        }
        // 校验最大可代收货款
        if(goodsbillMaster.getHelpAcceptPayment()!=null && goodsbillMaster.getHelpAcceptPayment().compareTo(parameters.getMaximumPayment())>0){
            throw new RuntimeException("修改失败，最大货款不得大于"+parameters.getMaximumPayment()+"元！");
        }
        String re = parameters.getMaximumPayment()
                +","+parameters.getMinCommisionReceivable()
                +","+parameters.getMaxCommisionReceivable()
                +","+parameters.getDeadline();

        goodsbillMaster.setAcceptprocedureRate(parameters.getCommisionRateRuling().toString());
        goodsbillMaster.setReceiveGoodsCustomerMobile(re);

        int result = goodsbillMasterMapper.updateSetAddCollectionBusinessByGmid(goodsbillMaster);
        if(result==0){
            throw new RuntimeException("添加失败，请刷新页面检查业务状态");
        }
    }

    @Override
    public void editBusiness(GoodsbillMaster goodsbillMaster) {
        // 先要获取指定业务的参数
        CollectionBusinessParameters parameters = collectionBusinessParametersMapper.selectBytype(goodsbillMaster.getSendGoodsCustomerMobile());
        if(parameters==null){
            throw new RuntimeException("修改失败，请检查业务是否存在");
        }
        // 校验最大可修改代收货款
        if(goodsbillMaster.getPayKickback()!=null && goodsbillMaster.getPayKickback().compareTo(parameters.getMaximumPayment())>0){
            throw new RuntimeException("修改失败，最大货款不得大于"+parameters.getMaximumPayment()+"元！");
        }
        String re = parameters.getMaximumPayment()
                +","+parameters.getMinCommisionReceivable()
                +","+parameters.getMaxCommisionReceivable()
                +","+parameters.getDeadline();

        goodsbillMaster.setAcceptprocedureRate(parameters.getCommisionRateRuling().toString());
        goodsbillMaster.setReceiveGoodsCustomerMobile(re);

        int result = goodsbillMasterMapper.updateSetEditCollectionBusinessByGmid(goodsbillMaster);
        if(result==0){
            throw new RuntimeException("修改失败，请刷新页面检查业务状态");
        }
    }



    /*--------------------------------工具方法------------------------------*/

    /**
     * @description: 判断排序字段和排序规则字符串是否非空
     * @param sidx 排序字段
     * @param sord 排序规则
     * @return: true则非空
     * @author: 邱斌雨
     * @date: 2019/10/25
     */
    private boolean checkOrderBy(String sidx,String sord){
        if(sidx != null && sord != null
                && sidx.trim().length() > 0
                && sord.trim().length() > 0){
            return true;
        }
        return false;
    }

    /**
     * @description: 大写转换为下划线+小写
     * @param param 需要转换的字符串
     * @return: 返回转换后的字符串
     * @author: 邱斌雨
     * @date: 2019/10/25
     */
    public static String upperCharToUnderLine(String param) {
        Pattern p = Pattern.compile("[A-Z]");
        if (param == null || param.equals("")) {
            return "";
        }
        StringBuilder builder = new StringBuilder(param);
        Matcher mc = p.matcher(param);
        int i = 0;
        while (mc.find()) {
            System.out.println(builder.toString());
            System.out.println("mc.start():" + mc.start() + ", i: " + i);
            System.out.println("mc.end():" + mc.start() + ", i: " + i);
            builder.replace(mc.start() + i, mc.end() + i, "_" + mc.group().toLowerCase());
            i++;
        }

        if ('_' == builder.charAt(0)) {
            builder.deleteCharAt(0);
        }
        return builder.toString();
    }
}
